﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MiniFox.Infrastructure
{
    /// <summary>
    /// 
    /// </summary>
    public class TreeNode : ITreeNode//, IComparable<ITreeNode>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="nodeData"></param>
        public TreeNode(object nodeData)
        {
            this.Data = nodeData;
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("id")]
        public object ID
        {
            get;
            internal set;
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("ordinal")]
        public int Ordinal
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("level")]
        public int Level
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("data")]
        public object Data 
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("children")]
        public IEnumerable<ITreeNode> Children
        {
            get;
            set;
        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="other"></param>
        ///// <returns></returns>
        //public int CompareTo(ITreeNode other)
        //{
        //    if (other == null)
        //        return 1;
        //    if (this.Ordinal < other.Ordinal) return -1;
        //    else if (this.Ordinal > other.Ordinal) return 1;
        //    else return 0;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator >(TreeNode left, TreeNode right)
        //{
        //    if (left == null) return false;
        //    if (right == null) return true;
        //    return left.Ordinal > right.Ordinal;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator <(TreeNode left, TreeNode right)
        //{
        //    if (left == null) return true;
        //    if (right == null) return false;
        //    return left.Ordinal < right.Ordinal;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator >=(TreeNode left, TreeNode right)
        //{
        //    if (left == null) return false;
        //    if (right == null) return true;
        //    return left.Ordinal >= right.Ordinal;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator <=(TreeNode left, TreeNode right)
        //{
        //    if (left == null) return true;
        //    if (right == null) return false;
        //    return left.Ordinal <= right.Ordinal;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator ==(TreeNode left, TreeNode right)
        //{
        //    if (left == null && right == null) return true;
        //    if (left != null && right != null) return left.Ordinal == right.Ordinal;
        //    else return false;

        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="left"></param>
        ///// <param name="right"></param>
        ///// <returns></returns>
        //public static bool operator !=(TreeNode left, TreeNode right)
        //{
        //    if (left == null && right == null) return false;
        //    if (left != null && right != null) return left.Ordinal != right.Ordinal;
        //    else return true;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns></returns>
        //public override int GetHashCode()
        //{
        //    return base.GetHashCode();
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="obj"></param>
        ///// <returns></returns>
        //public override bool Equals(object obj)
        //{
        //    var node = obj as TreeNode;
        //    if (node == null) return false;
        //    return this.Ordinal == node.Ordinal;
        //}
    }

    /// <summary>
    /// 
    /// </summary>
    public static class TreeNodeExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="treeNode"></param>
        /// <returns></returns>
        public static JToken ConvertToJsonObject(this ITreeNode treeNode)
        {
            const string children_key = "Children";
            JObject json = JObject.FromObject(treeNode.Data);
            if (json.ContainsKey(children_key))
                json.Remove(children_key);
            var array = new JArray();
            json.Add(children_key, array);
            var children = treeNode.Children;
            if (children != null && children.Count() > 0)
            {
                foreach (var node in children)
                {
                    array.Add(ConvertToJsonObject(node));
                }
            }

            return json;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="treeNode"></param>
        /// <returns></returns>
        public static JToken ConvertToJsonObject<T>(this TreeNode<T> treeNode)
        {
            const string children_key = "Children";
            JObject json = JObject.FromObject(treeNode.Data);
            if (json.ContainsKey(children_key))
                json.Remove(children_key);
            var array = new JArray();
            json.Add(children_key, array);
            var children = treeNode.Children;
            if (children != null && children.Count() > 0)
            {
                foreach (var node in children)
                {
                    array.Add(ConvertToJsonObject(node));
                }
            }

            return json;
        }
    }
}
